package org.jeecg.modules.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Maps;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.activiti.spring.ProcessEngineFactoryBean;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.modules.dto.ActProcessInstDto;
import org.jeecg.modules.mapper.ActBusinessMapper;
import org.jeecg.modules.service.IActProcessInstService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 流程定义相关Service
 *
 * @author ThinkGem
 * @version 2013-11-03
 */
@Service
//@Transactional(readOnly = true)
public class ActProcessInstServiceImpl implements IActProcessInstService {

    @Autowired
    private ActBusinessMapper businessMapper;

    @Autowired
    private ProcessEngineFactoryBean processEngineFactory;

    @Autowired
    private ProcessEngine processEngine;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private ISysBaseAPI sysBaseAPI;

    /**
     * 流程实例分页查询
     *
     * @param instance
     * @param pageNo
     * @param pageSize
     * @return
     */
    @Override
    public IPage<ActProcessInstDto> listPage(ProcessInstance instance, Integer pageNo, Integer pageSize) {

        final String procInsId = instance.getId();
        final String procDefKey = instance.getProcessDefinitionKey();

        ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();

        if (StringUtils.isNotBlank(procInsId)) {
            processInstanceQuery.processInstanceId(procInsId);
        }

        if (StringUtils.isNotBlank(procDefKey)) {
            processInstanceQuery.processDefinitionKey(procDefKey);
        }

        Page<ActProcessInstDto> page = new Page<ActProcessInstDto>(pageNo, pageSize);
        List<ProcessInstance> processInstanceList = processInstanceQuery.listPage((int) page.getCurrent() - 1, (int) page.getSize());

        page.setTotal(processInstanceQuery.count());
        page.setRecords(convertProcessInstanceList(processInstanceList));
        return page;
    }

    /**
     * 转换ProcessInstance -> ActProcessInstDto
     *
     * @param processInstanceList
     * @return
     */
    private List<ActProcessInstDto> convertProcessInstanceList(List<ProcessInstance> processInstanceList) {
        return Optional.ofNullable(processInstanceList).orElse(new ArrayList<>())
                .stream()
                .map(instance -> {
                    System.out.println(instance);
                    System.out.println(instance.isSuspended());
                    System.out.println(instance.getProcessVariables());
                    final ActProcessInstDto processInstDto = new ActProcessInstDto();
                    BeanUtils.copyProperties(instance, processInstDto);
                    return processInstDto;
                })
                .sorted(Comparator.comparing(ActProcessInstDto::getStartTime).reversed())
                .collect(Collectors.toList());
    }

    /**
     * 获取流程实例对象
     *
     * @param procInsId
     * @return
     */
    @Override
    @Transactional(readOnly = false)
    public ActProcessInstDto getProcInstance(String procInsId) {
        final ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(procInsId).singleResult();
        final ActProcessInstDto processInstDto = new ActProcessInstDto();
        BeanUtils.copyProperties(processInstance, processInstDto);
        return processInstDto;
    }

    /**
     * 启动流程
     *
     * @param procDefKey    流程定义KEY
     * @param businessTable 业务表表名
     * @param businessId    业务表编号
     * @return 流程实例ID
     */
    @Override
    @Transactional(readOnly = false)
    public String startProcess(String procDefKey, String businessTable, String businessId) {
        return startProcess(procDefKey, businessTable, businessId, "");
    }

    /**
     * 启动流程
     *
     * @param procDefKey    流程定义KEY
     * @param businessTable 业务表表名
     * @param businessId    业务表编号
     * @param title         流程标题，显示在待办任务标题
     * @return 流程实例ID
     */
    @Override
    @Transactional(readOnly = false)
    public String startProcess(String procDefKey, String businessTable, String businessId, String title) {
        Map<String, Object> vars = Maps.newHashMap();
        return startProcess(procDefKey, businessTable, businessId, title, vars);
    }

    /**
     * 启动流程
     *
     * @param procDefKey    流程定义KEY
     * @param businessTable 业务表表名
     * @param businessId    业务表编号
     * @param title         流程标题，显示在待办任务标题
     * @param vars          流程变量
     * @return 流程实例ID
     */
    @Override
    @Transactional(readOnly = false)
    public String startProcess(String procDefKey, String businessTable, String businessId, String title, Map<String, Object> vars) {

        // 用来设置启动流程的人员ID，引擎会自动把用户ID保存到activiti:initiator中
        // identityService.setAuthenticatedUserId(userId);

        // 设置流程变量
        if (vars == null) {
            vars = Maps.newHashMap();
        }

        // 设置流程标题
        if (StringUtils.isNotBlank(title)) {
            vars.put("title", title);
        }

        // 启动流程
        ProcessInstance procIns = runtimeService.startProcessInstanceByKey(procDefKey, businessTable + ":" + businessId, vars);
        runtimeService.setProcessInstanceName(procIns.getId(), title);
        // 更新业务表流程实例ID
        // businessMapper.updateProcInsIdByBusinessId(businessTable, businessId, procIns.getId());
        return procIns.getId();
    }

    /**
     * 挂起、激活流程实例
     *
     * @param procInstId
     * @param suspended
     * @return
     */
    @Override
    @Transactional(readOnly = false)
    public String updateState(String procInstId, Boolean suspended) {
        // 查询流程实例对象
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(procInstId).singleResult();

        String processInstanceId = processInstance.getId();

        // 得到当前流程定义的实例是否都为暂停状态
        boolean suspended2 = processInstance.isSuspended();
        System.out.println("流程实例【" + processInstanceId + "】的当前状态：" + (suspended2 ? "挂起" : "激活"));

        // 判断
        if (!suspended) {
            //说明是暂停，就可以激活操作
            runtimeService.activateProcessInstanceById(processInstanceId);
            System.out.println("流程：" + processInstanceId + "，激活");
            return "流程：" + processInstanceId + "，激活成功";
        } else {
            runtimeService.suspendProcessInstanceById(processInstanceId);
            System.out.println("流程：" + processInstanceId + "，挂起");
            return "流程：" + processInstanceId + "，挂起成功";
        }
    }

    @Override
    public void delete(String procInstId) {
        runtimeService.deleteProcessInstance(procInstId,"删除原因"); //删除流程
    }
}
